package me.zhengjie.minbearwcs.listener.agv.action;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDetailDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDetailHistoryDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionHistoryDao;
import me.zhengjie.minbearwcs.dao.inbound.inf.InboundOrderDao;
import me.zhengjie.minbearwcs.dao.inbound.inf.InboundOrderDetailDao;
import me.zhengjie.minbearwcs.dao.mission.inf.WcsMissionDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundOrderDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundStockUpRecordDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundTaskRecordDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.SortPalletDetailDao;
import me.zhengjie.minbearwcs.dao.rework.inf.ReworkTaskRecordDao;
import me.zhengjie.minbearwcs.dao.shifting.inf.ShiftingTaskRecordDao;
import me.zhengjie.minbearwcs.dao.stock.inf.MaterialStockDao;
import me.zhengjie.minbearwcs.dao.stock.inf.PalletDao;
import me.zhengjie.minbearwcs.dao.storage.inf.LargeStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.MediumStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.entity.DTO.agv.TUSK.TUSKFeedBackTask;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.actionEnum.AgvAction;
import me.zhengjie.minbearwcs.entity.DTO.inbound.wms.WmsPalletArriveExchangeArea;
import me.zhengjie.minbearwcs.entity.DTO.response.Resp;
import me.zhengjie.minbearwcs.entity.DTO.storage.wms.WmsStorageMediumBox;
import me.zhengjie.minbearwcs.entity.DTO.storage.wms.WmsStorageUpdate;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvContentPool;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMission;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMissionDetail;
import me.zhengjie.minbearwcs.entity.PO.agv.history.AgvMissionDetailHistory;
import me.zhengjie.minbearwcs.entity.PO.agv.history.AgvMissionHistory;
import me.zhengjie.minbearwcs.entity.PO.agv.missionEnum.AgvMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.inbound.InboundOrder;
import me.zhengjie.minbearwcs.entity.PO.wcs.inbound.InboundOrderDetail;
import me.zhengjie.minbearwcs.entity.PO.wcs.inbound.status.InboundOrderDetailStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.WcsMission;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.status.*;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.OutboundOrder;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.record.OutboundTaskRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.sort.SortPalletDetail;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.OutboundStockUpRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.stock.MaterialStock;
import me.zhengjie.minbearwcs.entity.PO.wcs.stock.Pallet;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.LargeStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.MediumStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.resource.WcsResource;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor3Or4.Storage3Or4FloorLocker;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.InboundStorage5Or6FloorLocker;
import me.zhengjie.minbearwcs.utils.JsonUtil;
import me.zhengjie.minbearwcs.utils.LogFileKey;
import me.zhengjie.minbearwcs.utils.WcsHpptUtil;
import me.zhengjie.observer.event.IWcsEvent;
import me.zhengjie.observer.listener.IWcsEventListener;
import me.zhengjie.observer.type.WcsEventType;
import me.zhengjie.observer.type.agv.AgvActionEventType;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Component
@RequiredArgsConstructor
public class PutAmendActionListener implements IWcsEventListener {

    private final AgvMissionDetailDao agvMissionDetailDao;
    private final AgvMissionDao agvMissionDao;
    private final SmallStorageDao smallStorageDao;
    private final AgvMissionHistoryDao agvMissionHistoryDao;
    private final AgvMissionDetailHistoryDao agvMissionDetailHistoryDao;
    private final WcsMissionDao wcsMissionDao;
    private final Storage3Or4FloorLocker storage3Or4FloorLocker;
    private final InboundStorage5Or6FloorLocker inboundStorage5Or6FloorLocker;
    private final WcsHpptUtil wcsHpptUtil;
    private final WcsResource wcsResource;
    private final InboundOrderDetailDao inboundOrderDetailDao;
    private final PalletDao palletDao;
    private final MaterialStockDao materialStockDao;
    private final MediumStorageDao mediumStorageDao;
    private final LargeStorageDao largeStorageDao;
    private final InboundOrderDao inboundOrderDao;
    private final OutboundStockUpRecordDao outboundStockUpRecordDao;
    private final OutboundTaskRecordDao outboundTaskRecordDao;
    private final OutboundOrderDao outboundOrderDao;
    private final SortPalletDetailDao sortPalletDetailDao;
    private final ShiftingTaskRecordDao shiftingTaskRecordDao;
    private final ReworkTaskRecordDao reworkTaskRecordDao;

    @Override
    public void onEvent(IWcsEvent wcsEvent) {
        /**
         *
         * 1.更新 agv任务明细
         * 2.更新agv任务
         * 3.把agv任务转移到历史任务表
         * 4.更新目标储位栈板号,并交换原储位栈板
         * 5.更新wcs任务状态
         */
        MDC.put(LogFileKey.KEY, LogFileKey.Module.AGV);
        TUSKFeedBackTask feedBackEvent = (TUSKFeedBackTask) wcsEvent.getSource();

        log.info("获取到agv上报修正 PUT信息：{}", JsonUtil.getJsonInfo(feedBackEvent));

        //1.更新 agv任务明细
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByTaskIdAndAction(feedBackEvent.getTaskId(), AgvAction.PUT);
        String oldPoint = agvMissionDetail.getPoint();

        agvMissionDetailDao.updateMarkTimePointAndIsCompleteById(
                agvMissionDetail.getId(),
                feedBackEvent.getTargetPoint(),
                LocalDateTime.now(),
                AgvContentPool.AGV_ACTION_COMPLETE
        );

        //2.更新agv任务
        agvMissionDao.updateAgvMissionFinish(
                feedBackEvent.getTaskId(),
                AgvMissionStatus.COMPLETE,
                agvMissionDetail.getTaskIndex(),
                LocalDateTime.now()
        );

        // 3.把agv任务转移到历史任务表
        List<AgvMissionDetail> agvMissionDetails = agvMissionDetailDao.selectByTaskId(feedBackEvent.getTaskId());
        for (AgvMissionDetail missionDetail : agvMissionDetails) {
            AgvMissionDetailHistory agvMissionDetailHistory = new AgvMissionDetailHistory(null, missionDetail.getTaskId(), missionDetail.getTaskIndex(),
                    missionDetail.getPoint(), missionDetail.getAction(), missionDetail.getMarkTime(),
                    missionDetail.getIsComplete());
            agvMissionDetailHistoryDao.insert(agvMissionDetailHistory);
            agvMissionDetailDao.deleteById(missionDetail.getId());
        }

        AgvMission agvMission = agvMissionDao.selectByTaskId(feedBackEvent.getTaskId());
        AgvMissionHistory agvMissionHistory = new AgvMissionHistory(null, agvMission.getTaskId(), agvMission.getMissionType(), agvMission.getTaskStatus(),
                agvMission.getPriority(), agvMission.getTargetCollection(), agvMission.getTotalActionNum(), agvMission.getCompleteActionNum(),
                agvMission.getAgvId(), agvMission.getPalletCode(), agvMission.getWcsMissionId(), agvMission.getWcsMissionType(),
                agvMission.getWcsMissionStatus(), agvMission.getCreateTime(), agvMission.getStartTime(), agvMission.getFinishTime());
        agvMissionHistoryDao.insert(agvMissionHistory);
        agvMissionDao.deleteById(agvMission.getId());


        // 4.更新目标储位栈板号
        MissionType wcsMissionType = MissionType.valueOf(agvMission.getWcsMissionType());
        switch (wcsMissionType) {
            case INBOUND_3_OR_4_FLOOR:
                storageInboundAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                storage3Or4FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                wcsResource.getExecutor().execute(() -> storageUpdate(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                ));
                break;
            case INBOUND_5_OR_6_FLOOR:
                storageInboundAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                inbound5Or6FStorageUpdate(
                        InboundMissionFor5Or6FloorStatus.valueOf(agvMission.getWcsMissionStatus()),
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                break;
            case OUTBOUND_STOCK_UP:
                storageOutboundStockUpAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                storage3Or4FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                break;
            case OUTBOUND_SORT:
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                break;
            //
            case OUTBOUND_AFTER_SORT:
            case OUTBOUND_WHOLE_PALLET:
                storageOutboundAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                wcsResource.getExecutor()
                        .execute(() -> storageOutboundUpdate(
                                feedBackEvent.getTargetPoint(),
                                agvMission.getPalletCode(),
                                wcsMissionDao.selectByMissionId(agvMission.getWcsMissionId())
                        ));
                break;
            case SHIFTING:
                storageShiftingAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                wcsResource.getExecutor()
                        .execute(() -> storageShiftingUpdate(
                                feedBackEvent.getTargetPoint(),
                                agvMission.getPalletCode(),
                                wcsMissionDao.selectByMissionId(agvMission.getWcsMissionId())
                        ));
                break;
            case REWORK_SHIFTING:
                storageReworkShiftingAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                wcsResource.getExecutor()
                        .execute(() -> storageShiftingUpdate(
                                feedBackEvent.getTargetPoint(),
                                agvMission.getPalletCode(),
                                wcsMissionDao.selectByMissionId(agvMission.getWcsMissionId())
                        ));
                break;
            case REWORK:
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                // TODO:返工栈板到达通知
                break;
            case OUTBOUND_SORT_EXCEPTION:
                storageOutboundSortExceptionAmend(feedBackEvent, oldPoint, agvMission.getPalletCode(), agvMission.getWcsMissionId());
                inboundStorage5Or6FloorLocker.arriveAndUnfreezeStorage(
                        feedBackEvent.getTargetPoint(),
                        agvMission.getPalletCode()
                );
                wcsResource.getExecutor()
                        .execute(() -> storageShiftingUpdate(
                                feedBackEvent.getTargetPoint(),
                                agvMission.getPalletCode(),
                                wcsMissionDao.selectByMissionId(agvMission.getWcsMissionId())
                        ));
                break;
        }


        // 5.更新wcs任务状态
        switch (wcsMissionType) {
            case INBOUND_3_OR_4_FLOOR:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        InboundMissionFor3Or4FloorStatus.FINISH.name()
                );
                break;
            case INBOUND_5_OR_6_FLOOR:
                change5FOr6FWcsMissionStatus(
                        InboundMissionFor5Or6FloorStatus.valueOf(agvMission.getWcsMissionStatus()),
                        agvMission.getWcsMissionId(),
                        agvMission.getPalletCode()
                );
                break;
            case OUTBOUND_STOCK_UP:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        OutboundStockUpMissionStatus.FINISH.name()
                );
                break;
            case OUTBOUND_WHOLE_PALLET:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        OutboundWholePalletMissionStatus.FINISH.name()
                );
                break;
            case OUTBOUND_SORT:
                changeOutboundSortWcsMissionStatus(
                        OutboundSortMissionStatus.valueOf(agvMission.getWcsMissionStatus()),
                        agvMission.getWcsMissionId(),
                        agvMission.getPalletCode()
                );
                break;
            case OUTBOUND_AFTER_SORT:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        OutboundAfterSortMissionStatus.FINISH.name()
                );
                break;
            case SHIFTING:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        ShiftingMissionStatus.FINISH.name()
                );
                break;
            case REWORK_SHIFTING:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        ReworkShiftingMissionStatus.FINISH.name()
                );
                break;
            case REWORK:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        ReworkMissionStatus.FINISH.name()
                );
                break;
            case OUTBOUND_SORT_EXCEPTION:
                wcsMissionDao.updateMissionStatusByMissionId(
                        agvMission.getWcsMissionId(),
                        OutboundSortExceptionStatus.FINISH.name()
                );
                break;
        }

        MDC.remove(LogFileKey.Module.AGV);
    }


    private synchronized void storageInboundAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) return;


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细
        try {
            Integer oldDetailId = Integer.parseInt(wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId));
            inboundOrderDetailDao.updateStoragePointById(oldDetailId, newSmallStorage.getQrPoint());

            InboundOrderDetail inboundOrderDetail = inboundOrderDetailDao.selectByPalletAndStoragePoint(newSmallStorage.getInboundFreezePallet(), newSmallStorage.getSmallStorageCode());
            inboundOrderDetailDao.updateStoragePointById(inboundOrderDetail.getId(), oldPoint);
        } catch (Exception e) {
            log.error("储位 {} 和 {} ， inboundOrderDetail 交换出错", newSmallStorage, oldSmallStorage, e);
        }
    }

    private synchronized void storageOutboundStockUpAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) return;


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细
        try {
            String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
            outboundStockUpRecordDao.updateDestinationSmallStorageByStockUpId(oldDetailId, newSmallStorage.getSmallStorageCode());

            OutboundStockUpRecord newOutboundStockUpRecord = outboundStockUpRecordDao.selectByPalletAndDestinationStorage(newSmallStorage.getInboundFreezePallet(), newSmallStorage.getSmallStorageCode());
            outboundStockUpRecordDao.updateDestinationSmallStorageByStockUpId(newOutboundStockUpRecord.getStockUpId(), oldPoint);
        } catch (Exception e) {
            log.error("储位 {} 和 {} ， outboundStockUpRecord 交换出错", newSmallStorage, oldSmallStorage, e);
        }

    }


    private synchronized void storageOutboundAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) return;


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细

        try {
            String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
            outboundTaskRecordDao.updateDestinationInfoByRecordId(oldDetailId, 1, newSmallStorage.getSmallStorageCode());

            OutboundTaskRecord outboundTaskRecord = outboundTaskRecordDao.selectByPalletAndDestinationStorage(newSmallStorage.getInboundFreezePallet(), newSmallStorage.getSmallStorageCode());
            outboundTaskRecordDao.updateDestinationInfoByRecordId(outboundTaskRecord.getOutboundRecordId(), 1, oldPoint);

        } catch (Exception e) {
            log.error("储位 {} 和 {} ， outboundStockUpRecord 交换出错", newSmallStorage, oldSmallStorage, e);
        }
    }


    private void change5FOr6FWcsMissionStatus(InboundMissionFor5Or6FloorStatus status, String wcsMissionId, String palletCode) {
        switch (status) {
            case PROCESSING_EXCHANGE_STORAGE:
                wcsMissionDao.updateMissionStatusByMissionId(
                        wcsMissionId,
                        InboundMissionFor5Or6FloorStatus.WAIT_FOR_CHECK_SKU.name()
                );
//                wcsResource.getExecutor().execute(() -> notifyWmsPalletArriveExchange(wcsMissionId));
                break;
            case PROCESSING_REAL_STORAGE:
            case PROCESSING_ROLLBACK_PRODUCTION_LINE:
                inboundWcsMisiionChangeFinish(status, wcsMissionId, palletCode);
                break;
        }
    }

    private void notifyWmsPalletArriveExchange(String wcsMissionId) {
        Integer inboundDetailId = Integer.parseInt(wcsMissionDao.selectAssociatedDetailIdByMissionId(wcsMissionId));
        InboundOrderDetail inboundOrderDetail = inboundOrderDetailDao.selectById(inboundDetailId);
        WmsPalletArriveExchangeArea wmsPalletArriveExchangeArea = new WmsPalletArriveExchangeArea(
                inboundOrderDetail.getPalletCode(),
                inboundOrderDetail.getInboundOrderCode(),
                inboundOrderDetail.getExchangePoint()
        );
        log.info("入库栈板到达入库交接区通知 : {}", wmsPalletArriveExchangeArea);
        Resp resp = wcsHpptUtil.notifyWmsPalletArriveExchangeArea(wmsPalletArriveExchangeArea);
        log.info("入库单号： {} ，栈板号：{} ，wms 收到 入库栈板到达入库交接区通知 ：{}",
                inboundOrderDetail.getInboundOrderCode(),
                inboundOrderDetail.getPalletCode(),
                resp
        );
    }


    private void inboundWcsMisiionChangeFinish(InboundMissionFor5Or6FloorStatus status, String wcsMissionId, String palletCode) {
        wcsMissionDao.updateMissionStatusByMissionId(
                wcsMissionId,
                InboundMissionFor5Or6FloorStatus.FINISH.name()
        );

        Integer detailId = Integer.parseInt(wcsMissionDao.selectAssociatedDetailIdByMissionId(wcsMissionId));

        switch (status) {
            case PROCESSING_REAL_STORAGE:
                inboundOrderDetailDao.updateStatusById(detailId, InboundOrderDetailStatus.COMPLETE);
                break;
            case PROCESSING_ROLLBACK_PRODUCTION_LINE:
                materialStockDao.deleteByPallet(palletCode);
                palletDao.deleteByPalletCode(palletCode);
                inboundOrderDetailDao.updateStatusById(detailId, InboundOrderDetailStatus.COMPLETE_ROLLBACK);
                break;
        }

        // TODO : 更新储位信息给wms

    }

    private void inbound5Or6FStorageUpdate(InboundMissionFor5Or6FloorStatus status, String smallStorageCode, String palletCode) {
        switch (status) {
            case PROCESSING_REAL_STORAGE:
            case PROCESSING_ROLLBACK_PRODUCTION_LINE:
                wcsResource.getExecutor().execute(() -> storageUpdate(smallStorageCode, palletCode));
        }
    }


    private void storageUpdate(String smallStorageCode, String palletCode) {
        MDC.put(LogFileKey.KEY, LogFileKey.Module.INBOUND);
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(smallStorageCode);
        MediumStorage mediumStorage = mediumStorageDao.selectByMediumStorage(smallStorage.getMediumStorageCode());
        LargeStorage largeStorage = largeStorageDao.selectByLargeStorageCode(mediumStorage.getLargeStorageCode());

        Pallet pallet = palletDao.selectByPalletCode(palletCode);
        InboundOrder inboundOrder = inboundOrderDao.selectByInboundOrderCode(pallet.getInboundOrderCode());

        // 入库不需要箱
//        List<MaterialStock> materialStockList = materialStockDao.selectByPalletCode(palletCode);
//
//        List<String> smallBoxCollect = materialStockList.stream()
//                .filter(a -> a.getMediumBoxCode() == null)
//                .map(MaterialStock::getSmallBoxCode)
//                .collect(Collectors.toList());
//
//        List<WmsStorageMediumBox> mediumList = materialStockList.stream()
//                .collect(Collectors.groupingBy(MaterialStock::getMediumBoxCode))
//                .entrySet()
//                .stream()
//                .map(a -> {
//                    List<String> smallTemp = a.getValue().stream()
//                            .map(MaterialStock::getSmallBoxCode)
//                            .collect(Collectors.toList());
//                    return new WmsStorageMediumBox(a.getKey(), smallTemp);
//                })
//                .collect(Collectors.toList());

        List<String> orderCodeList = new ArrayList<>();
        orderCodeList.add(inboundOrder.getInboundOrderCode());

        WmsStorageUpdate wmsStorageUpdate = new WmsStorageUpdate(palletCode, largeStorage.getLargeStorageCode(), mediumStorage.getMediumStorageCode(),
                smallStorageCode, largeStorage.getFloorNum().toString(), palletCode, smallStorage.getQrPoint(),
                orderCodeList, inboundOrder.getOrderType(), new ArrayList<>(), new ArrayList<>());

        try {
            log.info("wcs通知wms 入库栈板储位更新信息 : {}", wmsStorageUpdate);
            Resp resp = wcsHpptUtil.wmsStorageUpdate(wmsStorageUpdate);
            log.info("单号： {} , 类型：{} ，栈板号：{} ，wms 收到 栈板储位更新信息 ：{}",
                    inboundOrder.getInboundOrderCode(),
                    inboundOrder.getOrderType(),
                    palletCode,
                    resp
            );
        } catch (Exception e) {
            log.error("wcs通知wms 入库栈板储位更新信息失败", e);
        }
        MDC.remove(LogFileKey.Module.INBOUND);
    }


    private void storageOutboundUpdate(String smallStorageCode, String palletCode, WcsMission wcsMission) {
        MDC.put(LogFileKey.KEY, LogFileKey.Module.OUTBOUND);
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(smallStorageCode);
        MediumStorage mediumStorage = mediumStorageDao.selectByMediumStorage(smallStorage.getMediumStorageCode());
        LargeStorage largeStorage = largeStorageDao.selectByLargeStorageCode(mediumStorage.getLargeStorageCode());


        List<String> orderCodeList = new ArrayList<>();
        String orderType = null;
        String material_code = "";
        boolean isSort = false;
        if (wcsMission.getOrderCode() != null) {
            OutboundOrder outboundOrder = outboundOrderDao.selectByOrderCode(wcsMission.getOrderCode());
            orderCodeList.add(outboundOrder.getOutboundOrderCode());
            orderType = outboundOrder.getOrderType();
            Pallet pallet = palletDao.selectByPalletCode(palletCode);
            material_code = pallet.getMaterialCode();
        } else {
            List<SortPalletDetail> sortPalletDetailList = sortPalletDetailDao.selectByPalletCode(palletCode);
            List<String> collect = sortPalletDetailList.stream()
                    .map(SortPalletDetail::getOutboundOrderCode)
                    .collect(Collectors.toList());
            orderCodeList = collect;
            OutboundOrder outboundOrder = outboundOrderDao.selectByOrderCode(orderCodeList.get(0));
            orderType = outboundOrder.getOrderType();
            isSort = true;
        }

        List<String> smallBoxCollect = new ArrayList<>();
        List<WmsStorageMediumBox> mediumList = new ArrayList<>();

        if (isSort) {
            List<MaterialStock> materialStockList = materialStockDao.selectByPalletCode(palletCode);

            smallBoxCollect = materialStockList.stream()
                    .filter(a -> a.getMediumBoxCode() == null)
                    .map(MaterialStock::getSmallBoxCode)
                    .collect(Collectors.toList());

            mediumList = materialStockList.stream()
                    .filter(a -> a.getMediumBoxCode() == null)
                    .collect(Collectors.groupingBy(MaterialStock::getMediumBoxCode))
                    .entrySet()
                    .stream()
                    .map(a -> {
                        List<String> smallTemp = a.getValue().stream()
                                .map(MaterialStock::getSmallBoxCode)
                                .collect(Collectors.toList());
                        return new WmsStorageMediumBox(a.getKey(), smallTemp);
                    })
                    .collect(Collectors.toList());
        }


        WmsStorageUpdate wmsStorageUpdate = new WmsStorageUpdate(palletCode, largeStorage.getLargeStorageCode(), mediumStorage.getMediumStorageCode(),
                smallStorageCode, largeStorage.getFloorNum().toString(), smallStorage.getQrPoint(), material_code,
                orderCodeList, orderType, smallBoxCollect, mediumList);

        try {
            log.info("wcs通知wms 出库栈板储位更新信息 : {}", wmsStorageUpdate);
            Resp resp = wcsHpptUtil.wmsStorageUpdate(wmsStorageUpdate);
            log.info("单号： {} , 类型：{} ，栈板号：{} ，wms 收到 栈板储位更新信息 ：{}",
                    orderCodeList,
                    orderType,
                    palletCode,
                    resp
            );
        } catch (Exception e) {
            log.error("wcs通知wms 出库栈板储位更新信息失败", e);
        }
        MDC.remove(LogFileKey.Module.OUTBOUND);
    }

    private void changeOutboundSortWcsMissionStatus(OutboundSortMissionStatus status, String wcsMissionId, String palletCode) {
        switch (status) {
            case PROCESSING:
            case PROCESSING_CONTINUE_SORT:
                wcsMissionDao.updateMissionStatusByMissionId(
                        wcsMissionId,
                        OutboundSortMissionStatus.WAIT_FOR_SORT.name()
                );
                break;
            case PROCESSING_EXCEPTION_AREA:
                wcsMissionDao.updateMissionStatusByMissionId(
                        wcsMissionId,
                        OutboundSortMissionStatus.WAIT_FOR_CHECK_EXCEPTION.name()
                );
                break;
            case PROCESSING_MANTISSA_AREA_5F_STORAGE:
                wcsMissionDao.updateMissionStatusByMissionId(
                        wcsMissionId,
                        OutboundSortMissionStatus.FINISH.name()
                );
                break;
        }
    }


    private void storageShiftingUpdate(String smallStorageCode, String palletCode, WcsMission wcsMission) {
        MDC.put(LogFileKey.KEY, LogFileKey.Module.SHIFTING);
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(smallStorageCode);
        MediumStorage mediumStorage = mediumStorageDao.selectByMediumStorage(smallStorage.getMediumStorageCode());
        LargeStorage largeStorage = largeStorageDao.selectByLargeStorageCode(mediumStorage.getLargeStorageCode());
        Pallet pallet = palletDao.selectByPalletCode(palletCode);

        List<String> smallBoxCollect;
        List<WmsStorageMediumBox> mediumList;


        List<MaterialStock> materialStockList = materialStockDao.selectByPalletCode(palletCode);

        smallBoxCollect = materialStockList.stream()
                .filter(a -> a.getMediumBoxCode() == null)
                .map(MaterialStock::getSmallBoxCode)
                .collect(Collectors.toList());

        mediumList = materialStockList.stream()
                .filter(a -> a.getMediumBoxCode() != null)
                .collect(Collectors.groupingBy(MaterialStock::getMediumBoxCode))
                .entrySet()
                .stream()
                .map(a -> {
                    List<String> smallTemp = a.getValue().stream()
                            .map(MaterialStock::getSmallBoxCode)
                            .collect(Collectors.toList());
                    return new WmsStorageMediumBox(a.getKey(), smallTemp);
                })
                .collect(Collectors.toList());


        WmsStorageUpdate wmsStorageUpdate = new WmsStorageUpdate(palletCode, largeStorage.getLargeStorageCode(), mediumStorage.getMediumStorageCode(),
                smallStorageCode, largeStorage.getFloorNum().toString(), smallStorage.getQrPoint(), pallet.getMaterialCode(),
                null, null, smallBoxCollect, mediumList);

        try {
            log.info("wcs通知wms 出库栈板储位更新信息 : {}", JsonUtil.getJsonInfo(wmsStorageUpdate));
            Resp resp = wcsHpptUtil.wmsShiftingStorageUpdate(wmsStorageUpdate);
            log.info("移库单号： {}  ，栈板号：{} ，wms 收到 移库栈板储位更新信息 ：{}",
                    wcsMission.getAssociatedDetailId(),
                    palletCode,
                    JsonUtil.getJsonInfo(resp)
            );
        } catch (Exception e) {
            log.error("wcs通知wms 出库栈板储位更新信息失败", e);
        }
        MDC.remove(LogFileKey.Module.OUTBOUND);
    }


    private synchronized void storageShiftingAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) {
            try {
                String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
                shiftingTaskRecordDao.updateEndPointByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
            } catch (Exception e) {
                log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", feedBackEvent.getTargetPoint(), oldPoint, e);
            }
            return;
        }


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细

        try {
            String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
            shiftingTaskRecordDao.updateEndPointByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
        } catch (Exception e) {
            log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", newSmallStorage, oldSmallStorage, e);
        }
    }


    private synchronized void storageReworkShiftingAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) {
            try {
                String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
                reworkTaskRecordDao.updateEndPointByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
            } catch (Exception e) {
                log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", feedBackEvent.getTargetPoint(), oldPoint, e);
            }
            return;
        }


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细

        try {
            String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
            reworkTaskRecordDao.updateEndPointByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
        } catch (Exception e) {
            log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", newSmallStorage, oldSmallStorage, e);
        }
    }



    private synchronized void storageOutboundSortExceptionAmend(TUSKFeedBackTask feedBackEvent, String oldPoint, String palletCode, String oldWcsMissionId) {
        /**
         *
         * 1.通过小储位表找到原来的目标栈板
         * 2.通过原栈板找到交换的小储位
         * 3.交换栈板储位
         * 4.更新agv任务点位
         * 5.更新当前任务储位
         *
         */
        if (feedBackEvent.getTargetPoint().equals(oldPoint)) {
            try {
                String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
                outboundTaskRecordDao.updateDestinationStorageByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
            } catch (Exception e) {
                log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", feedBackEvent.getTargetPoint(), oldPoint, e);
            }
            return;
        }


        // 1.找到新旧两个储位
        String targetPoint = feedBackEvent.getTargetPoint();
        SmallStorage newSmallStorage = smallStorageDao.selectBySmallStorage(targetPoint);
        SmallStorage oldSmallStorage = smallStorageDao.selectBySmallStorage(oldPoint);

        String newPalletCode = newSmallStorage.getInboundFreezePallet();

        // 2.新储位信息转移到旧储位
        // 2.1 处理agv任务
        AgvMissionDetail agvMissionDetail = agvMissionDetailDao.selectByPointAndAction(newSmallStorage.getSmallStorageCode(), AgvAction.PUT);
        agvMissionDetailDao.updatePointById(agvMissionDetail.getId(), oldSmallStorage.getSmallStorageCode());

        // 2.2 处理储位信息
        smallStorageDao.updateInboundFreezePallet(oldSmallStorage.getId(), newSmallStorage.getInboundFreezePallet());
        smallStorageDao.updateInboundFreezePallet(newSmallStorage.getId(), palletCode);


        // 2.3 更新入库明细

        try {
            String oldDetailId = wcsMissionDao.selectAssociatedDetailIdByMissionId(oldWcsMissionId);
            outboundTaskRecordDao.updateDestinationStorageByRecordId(oldDetailId, feedBackEvent.getTargetPoint());
        } catch (Exception e) {
            log.error("储位 {} 和 {} ， shiftingTaskRecord 交换出错", newSmallStorage, oldSmallStorage, e);
        }
    }


    @Override
    public WcsEventType getEventType() {
        return AgvActionEventType.PUT_AMEND;
    }
}
